import json
import os
import tempfile
from urllib.parse import quote

import pandas as pd
from django.conf import settings
from django.http import JsonResponse, FileResponse
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods


# 处理Excel文件数据 ============================================
class GetExcelView(View):
    def post(self, request):
        files = request.FILES
        # If no files found, try to parse the raw multipart body (fallback)
        if not files:
            try:
                from django.http.multipartparser import MultiPartParser
                parser = MultiPartParser(request.META, request, request.upload_handlers)
                post, files = parser.parse()
            except Exception as e:
                return JsonResponse({
                    'code': 400,
                    'msg': '未收到文件或请求方法不正确',
                    'debug': str(e),
                    'content_type': request.content_type,
                }, status=400)

        # support common field names for uploads
        file_field = None
        for candidate in ('file', 'File', 'upload', 'file0', 'files', 'data'):
            if candidate in files:
                file_field = candidate
                break

        # if no named field matched, pick the first uploaded file if present
        if not file_field and files:
            try:
                file_field = next(iter(files.keys()))
            except StopIteration:
                file_field = None

        if not file_field:
            return JsonResponse({
                'code': 400,
                'msg': '未收到文件或请求方法不正确',
                'content_type': request.content_type,
                'files_keys': list(files.keys()) if files else []
            }, status=400)

        excel_file = files.get(file_field)

        # Basic validation
        file_name = getattr(excel_file, 'name', '')
        file_extension = os.path.splitext(file_name)[1].lower() if file_name else ''
        supported_extensions = ['.xls', '.xlsx', '.xlsm']
        if file_extension and file_extension not in supported_extensions:
            return JsonResponse({
                'code': 400,
                'msg': f'不支持的文件格式: {file_extension}。请上传 .xls, .xlsx 或 .xlsm 格式的文件'
            })

        try:
            # write uploaded file chunks to a temp file and parse with pandas
            suffix = file_extension or ''
            with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
                for chunk in excel_file.chunks():
                    tmp.write(chunk)
                tmp_path = tmp.name

            try:
                df = pd.read_excel(tmp_path, header=1)
                df = df.fillna('')
                data = df.to_dict(orient='records')

                try:
                    os.unlink(tmp_path)
                except Exception:
                    pass

                return JsonResponse({
                    'code': 200,
                    'msg': 'success',
                    'data': data,
                    'file_info': {
                        'original_name': file_name,
                        'rows_count': len(data),
                        'columns_count': len(df.columns) if not df.empty else 0
                    }
                })
            except Exception as e:
                try:
                    os.unlink(tmp_path)
                except Exception:
                    pass
                print('读取Excel失败：', e)
                return JsonResponse({
                    'code': 500,
                    'msg': f'读取Excel文件失败: {str(e)}'
                })
        except Exception as e:
            print('文件处理失败：', e)
            return JsonResponse({
                'code': 500,
                'msg': f'文件处理失败: {str(e)}'
            })


@csrf_exempt
def DownloadFile(request):
    """
        文件下载API接口
        支持GET和POST请求
        """
    try:
        # 获取文件名参数
        if request.method == 'GET':
            file_name = request.GET.get('name')
        else:  # POST
            # 支持JSON和form-data格式
            if request.content_type == 'application/json':
                data = json.loads(request.body)
                file_name = data.get('name')
            else:
                file_name = request.POST.get('name')

        # 验证参数
        if not file_name:
            return JsonResponse({
                'code': '500',
                'msg': '缺少文件名参数!'
            }, status=500)

        # 安全检查：防止目录遍历攻击
        if '..' in file_name or file_name.startswith('/') or '\\' in file_name:
            return JsonResponse({
                'code': '500',
                'msg': '无效的文件名!'
            }, status=500)

        # 构建完整文件路径
        file_path = os.path.join(settings.MEDIA_ROOT, file_name)
        print(file_path)
        # 检查文件是否存在
        if not os.path.exists(file_path):
            return JsonResponse({
                'code': '404',
                'msg': '文件不存在!'
            }, status=404)

        # 检查是否为文件（不是目录）
        if not os.path.isfile(file_path):
            return JsonResponse({
                'code': '500',
                'msg': '路径不是文件!'
            }, status=500)

        # 打开文件并返回文件响应
        file = open(file_path, 'rb')
        response = FileResponse(file)

        encoded_name = quote(file_name)
        # 设置响应头
        response['Content-Disposition'] = f"attachment; filename={encoded_name}"

        # 设置Content-Type
        # 可以根据需要扩展更多的MIME类型
        mime_types = {
            '.pdf': 'application/pdf',
            '.jpg': 'image/jpeg',
            '.jpeg': 'image/jpeg',
            '.png': 'image/png',
            '.gif': 'image/gif',
            '.txt': 'text/plain',
            '.doc': 'application/msword',
            '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            '.xls': 'application/vnd.ms-excel',
            '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            '.zip': 'application/zip',
            '.rar': 'application/x-rar-compressed',
        }

        ext = os.path.splitext(file_path)[1].lower()
        response['Content-Type'] = mime_types.get(ext, 'application/octet-stream')

        return response

    except Exception as e:
        return JsonResponse({
            'code': '500',
            'msg': f'服务器错误: {str(e)}'
        }, status=500)


@csrf_exempt
@require_http_methods(["POST"])  # 限制只接受POST请求
def ImportExcel(request):
    # Try to obtain uploaded files. Some clients may send different field names
    files = request.FILES

    # If no files found, try to parse the raw multipart body (fallback)
    if not files:
        try:
            from django.http.multipartparser import MultiPartParser
            parser = MultiPartParser(request.META, request, request.upload_handlers)
            post, files = parser.parse()
        except Exception as e:
            return JsonResponse({
                'code': 400,
                'msg': '未收到文件或请求方法不正确',
                'debug': str(e),
                'content_type': request.content_type,
            }, status=400)

    # support common field names for uploads
    file_field = None
    for candidate in ('file', 'File', 'upload', 'file0', 'files', 'data'):
        if candidate in files:
            file_field = candidate
            break

    # if no named field matched, pick the first uploaded file if present
    if not file_field and files:
        try:
            file_field = next(iter(files.keys()))
        except StopIteration:
            file_field = None

    if not file_field:
        return JsonResponse({
            'code': 400,
            'msg': '未收到文件或请求方法不正确',
            'content_type': request.content_type,
            'files_keys': list(files.keys()) if files else []
        }, status=400)

    excel_file = files.get(file_field)

    # Basic validation
    file_name = getattr(excel_file, 'name', '')
    file_extension = os.path.splitext(file_name)[1].lower() if file_name else ''
    supported_extensions = ['.xls', '.xlsx', '.xlsm']
    if file_extension and file_extension not in supported_extensions:
        return JsonResponse({
            'code': 400,
            'msg': f'不支持的文件格式: {file_extension}。请上传 .xls, .xlsx 或 .xlsm 格式的文件'
        })

    try:
        # write uploaded file chunks to a temp file and parse with pandas
        suffix = file_extension or ''
        with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
            for chunk in excel_file.chunks():
                tmp.write(chunk)
            tmp_path = tmp.name

        try:
            df = pd.read_excel(tmp_path, header=1)
            df = df.fillna('')
            data = df.to_dict(orient='records')

            try:
                os.unlink(tmp_path)
            except Exception:
                pass

            return JsonResponse({
                'code': 200,
                'msg': 'success',
                'data': data,
                'file_info': {
                    'original_name': file_name,
                    'rows_count': len(data),
                    'columns_count': len(df.columns) if not df.empty else 0
                }
            })
        except Exception as e:
            try:
                os.unlink(tmp_path)
            except Exception:
                pass
            print('读取Excel失败：', e)
            return JsonResponse({
                'code': 500,
                'msg': f'读取Excel文件失败: {str(e)}'
            })
    except Exception as e:
        print('文件处理失败：', e)
        return JsonResponse({
            'code': 500,
            'msg': f'文件处理失败: {str(e)}'
        })
